package org.light.simpleauth.verb;

import java.util.ArrayList;
import java.util.List;

import org.light.core.Verb;
import org.light.core.Writeable;
import org.light.domain.Domain;
import org.light.domain.Dropdown;
import org.light.domain.Field;
import org.light.domain.JavascriptBlock;
import org.light.domain.JavascriptMethod;
import org.light.domain.Method;
import org.light.domain.Signature;
import org.light.domain.Statement;
import org.light.domain.StatementList;
import org.light.domain.Type;
import org.light.domain.Var;
import org.light.easyui.EasyUIPositions;
import org.light.exception.ValidateException;
import org.light.oracle.generator.MybatisOracleSqlReflector;
import org.light.utils.MybatisSqlReflector;
import org.light.utils.PgsqlReflector;
import org.light.utils.StringUtil;
import org.light.utils.WriteableUtil;

public class CloneUser extends Verb implements EasyUIPositions {

	@Override
	public Method generateDaoImplMethod() throws Exception {
		if (this.denied) return null;
		else {
			Method method = new Method();
			method.setStandardName("Clone" + StringUtil.capFirst(this.domain.getStandardName()));
			method.addSignature(new Signature(1, "db","*sql.DB"));
			method.addSignature(new Signature(2, "tx","*sql.Tx"));
			method.addSignature(new Signature(3, this.domain.getDomainId().getLowerFirstFieldName(),this.domain.getDomainId().getFieldType()));
			method.setReturnType(this.domain.getDomainId().getRawType());
			
			List<Writeable> sList = new ArrayList<Writeable>();
			
			if (StringUtil.isBlank(this.getDbType())||this.getDbType().equalsIgnoreCase("MariaDB")||this.getDbType().equalsIgnoreCase("MySQL")) {
				sList.add(new Statement(1000L,1,"sql := \""+MybatisSqlReflector.generateFindByIdStatement(domain)+"\""));
			}else if (this.getDbType().equalsIgnoreCase("PostgreSQL")||this.getDbType().equalsIgnoreCase("pgsql")) {
				sList.add(new Statement(1000L,1,"sql := \""+ PgsqlReflector.generateFindByIdStatement(domain)+"\""));
			}else if (this.getDbType().equalsIgnoreCase("Oracle")) {
				sList.add(new Statement(1000L,1,"sql := \""+ MybatisOracleSqlReflector.generateFindByIdStatement(domain)+"\""));
			}	
			
			sList.add(new Statement(2000L,1,"stmt, err := db.Prepare(sql)"));
			sList.add(new Statement(3000L,1,"defer stmt.Close()"));
			sList.add(new Statement(4000L,1,"if err != nil {"));
			sList.add(new Statement(5000L,2,"panic(err)"));
			sList.add(new Statement(6000L,1,"}"));
			sList.add(new Statement(7000L,1,"row := stmt.QueryRow(girlId)"));
			sList.add(new Statement(8000L,0,""));
			
			if (this.domain.getDomainName()!=null) sList.add(new Statement(8000L,1,"var "+this.domain.getDomainName().getLowerFirstFieldName()+" "+ this.domain.getDomainName().getFieldTypeWithParseImage()));
			if (this.domain.getActive()!=null) {
				if ("oracle".equalsIgnoreCase(this.getDbType()))  sList.add(new Statement(9000L,1,"var "+this.domain.getActive().getLowerFirstFieldName()+" int"));
				else sList.add(new Statement(10000L,1,"var "+this.domain.getActive().getLowerFirstFieldName()+" "+ this.domain.getActive().getFieldTypeWithParseImage()));
			}
			long serial = 11000L;
			for (Field f:this.domain.getPlainFields()) {
				if ((f instanceof Dropdown || "int64".equals(f.getFieldType()))&& "oracle".equalsIgnoreCase(this.domain.getDbType())){
					sList.add(new Statement(serial,1,"var "+f.getLowerFirstFieldName()+" NullString"));
					serial += 1000L;
					continue;
				}
				if ("oracle".equalsIgnoreCase(this.getDbType())&&"bool".equals(f.getFieldType())) {
					sList.add(new Statement(serial,1,"var "+f.getLowerFirstFieldName()+" int"));
					serial += 1000L;
				}else {
					sList.add(new Statement(serial,1,"var "+f.getLowerFirstFieldName()+" "+ f.getFieldNullTypeWithParseImage()));
					serial += 1000L;
				}
			}
			StringBuilder sb = new StringBuilder();
			for (Field f:this.domain.getFields()) {
				sb.append("&").append(f.getLowerFirstFieldName()).append(",");
			}
			String fieldsQuery = sb.toString();
			fieldsQuery=fieldsQuery.substring(0,fieldsQuery.length()-1);
			
			sList.add(new Statement(serial,0,""));
			sList.add(new Statement(serial+1000L,1,"err = row.Scan("+fieldsQuery+")"));
			sList.add(new Statement(serial+1500L,1,"if err != nil {"));
			sList.add(new Statement(serial+2000L,2,"panic(err)"));
			sList.add(new Statement(serial+3000L,1,"}"));
			sList.add(new Statement(serial+4000L,1,"girlName = findIndexedName(db, girlName)"));
			sList.add(new Statement(serial+5000L,0,""));
			
			if (StringUtil.isBlank(this.getDbType())||this.getDbType().equalsIgnoreCase("MariaDB")||this.getDbType().equalsIgnoreCase("MySQL")) {
				sList.add(new Statement(serial+6000L,1,"sql = \""+MybatisSqlReflector.generateInsertSql(domain)+"\""));
			}else if (this.getDbType().equalsIgnoreCase("PostgreSQL")||this.getDbType().equalsIgnoreCase("pgsql")) {
				sList.add(new Statement(serial+6000L,1,"sql = \""+ PgsqlReflector.generateInsertSql(domain)+"\""));
			}else if (this.getDbType().equalsIgnoreCase("Oracle")) {
				sList.add(new Statement(serial+6000L,1,"sql = \""+ MybatisOracleSqlReflector.generateInsertSql(domain)+"\""));
			}
			
			sList.add(new Statement(serial+7000L,1,"stmt, err = db.Prepare(sql)"));
			sList.add(new Statement(serial+8000L,1,"defer stmt.Close()"));
			sList.add(new Statement(serial+9000L,1,"if err != nil {"));
			sList.add(new Statement(serial+10000L,2,"panic(err)"));
			sList.add(new Statement(serial+11000L,1,"}"));
			
			StringBuilder sb2 = new StringBuilder();
			for (Field f:this.domain.getFieldsWithoutId()) {
				if (this.domain.getPlainFields().contains(f) && "".equalsIgnoreCase(f.getFieldType())) {
					sb2.append("utils.ParseNullString(").append(f.getLowerFirstFieldName()).append("),");
				}
				else {
					sb2.append(f.getLowerFirstFieldName()).append(",");
				}
			}
			String fieldsQuery2 = sb2.toString();
			if (fieldsQuery.endsWith(",")) fieldsQuery2=fieldsQuery2.substring(0,fieldsQuery2.length()-1);
			
			sList.add(new Statement(serial+12000L,1,"result, err := stmt.Exec("+fieldsQuery2+")"));
			sList.add(new Statement(serial+13000L,1,"if err != nil {"));
			sList.add(new Statement(serial+14000L,2,"panic(err)"));
			sList.add(new Statement(serial+15000L,1,"}"));
			sList.add(new Statement(serial+16000L,1,"var returnid int64"));
			sList.add(new Statement(serial+17000L,1,"returnid, err = result.LastInsertId()"));
			sList.add(new Statement(serial+18000L,1,"return returnid"));
			
			method.setMethodStatementList(WriteableUtil.merge(sList));
			return method;
		}
	}	

	@Override
	public Method generateDaoMethodDefinition() throws Exception {
		if (this.denied) return null;
		else {
			Method method = new Method();
			method.setStandardName("add"+StringUtil.capFirst(this.domain.getStandardName()));
			method.setReturnType(new Type("void"));
			method.setThrowException(true);
			method.addAdditionalImport("java.util.List");
			method.addAdditionalImport(this.domain.getPackageToken()+ "."+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix());
			
			method.addSignature(new Signature(1, StringUtil.lowerFirst(this.domain.getStandardName()), this.domain.getType()));
			return method;
		}
	}

	@Override
	public Method generateServiceMethodDefinition() throws Exception {
		if (this.denied) return null;
		else {
			Method method = new Method();
			method.setStandardName("add"+StringUtil.capFirst(this.domain.getStandardName()));
			method.setReturnType(new Type("bool"));
			method.setThrowException(true);
			method.addAdditionalImport("java.util.List");
			method.addAdditionalImport(this.domain.getPackageToken()+ "."+this.domain.getDomainSuffix()+"."+this.domain.getCapFirstDomainNameWithSuffix());
			method.addSignature(new Signature(1, StringUtil.lowerFirst(this.domain.getStandardName()), this.domain.getType()));
			return method;
		}
	}

	@Override
	public Method generateServiceImplMethod() throws Exception  {
		if (this.denied) return null;
		else {
			Method method = new Method();
			method.setStandardName("Clone" + StringUtil.capFirst(this.domain.getStandardName()));
			method.setReturnType(this.domain.getDomainId().getRawType());
			method.setReturnType(this.domain.getDomainId().getFieldRawType());
			method.addSignature(new Signature(1,this.domain.getDomainId().getLowerFirstFieldName(),this.domain.getDomainId().getFieldType()));
			
			List<Writeable> sList = new ArrayList<Writeable>();
			sList.add(new Statement(1000L,1,"db := database.DB"));
			sList.add(new Statement(2000L,1,"tx, err := db.Begin()"));
			sList.add(new Statement(3000L,1,"if err != nil {"));
			sList.add(new Statement(4000L,2,"panic(err)"));
			sList.add(new Statement(5000L,1,"}"));
			sList.add(new Statement(6000L,1,"retVal := "+this.domain.getDaoimplSuffix()+".Clone"+this.domain.getCapFirstDomainName()+"(db, tx, "+this.domain.getDomainId().getLowerFirstFieldName()+")"));
			sList.add(new Statement(7000L,1,"tx.Commit()"));
			sList.add(new Statement(8000L,1,"return retVal"));
			method.setMethodStatementList(WriteableUtil.merge(sList));
			return method;
		}
	}
	public CloneUser(){
		super();
		this.setLabel("克隆");
	}
	
	public CloneUser(Domain domain) throws ValidateException{
		super();
		this.domain = domain;
		this.denied = domain.isVerbDenied("Clone");
		this.setVerbName("Clone"+StringUtil.capFirst(this.domain.getStandardName()));
		this.setLabel("克隆");
		if  (domain.getLanguage().equalsIgnoreCase("english"))  this.setLabel("Add");
	}

	@Override
	public Method generateControllerMethod() throws Exception {
		if (this.denied) return null;
		else {
			Method method = new Method();
			method.setStandardName("Clone"+StringUtil.capFirst(this.domain.getStandardName()));
			method.addSignature(new Signature(1,"c","*gin.Context"));
			
			List<Writeable> sList = new ArrayList<Writeable>();
			sList.add(new Statement(1000L,1,"idStr := utils.DefaultFormQuery(c,\""+this.domain.getDomainId().getLowerFirstFieldName()+"\",\"\")"));
			sList.add(new Statement(2000L,1,this.domain.getDomainId().getLowerFirstFieldName()+", _ := strconv.ParseInt(idStr, 10, 64)"));
			sList.add(new Statement(3000L,1,this.domain.getServiceimplSuffix()+".Clone"+this.domain.getCapFirstDomainName()+"("+this.domain.getDomainId().getLowerFirstFieldName()+")"));
			sList.add(new Statement(4000L,1,"SendResponse(c, nil, nil, 0, true)"));
			method.setMethodStatementList(WriteableUtil.merge(sList));
			
			return method;
		}
	}
	
	@Override
	public JavascriptBlock generateEasyUIJSButtonBlock() throws Exception {
		if (this.denied) return null;
		else {
			JavascriptBlock block = new JavascriptBlock();
			block.setSerial(100);
			block.setStandardName("clone"+domain.getCapFirstDomainName());
			StatementList sl = new StatementList();
			sl.add(new Statement(1000,0, "{"));
			if (this.domain.getLanguage().equalsIgnoreCase("english")) {
				sl.add(new Statement(2000, 1, "text:'Clone',"));
			}else {
				sl.add(new Statement(2000,1, "text:'克隆',"));
			}
			sl.add(new Statement(3000,1, "iconCls:'icon-add',"));
			sl.add(new Statement(4000,1, "handler:function(){ "));
			sl.add(new Statement(5000,2, "var rows = $(\"#"+this.detailPrefix+"dg\").datagrid(\"getChecked\");"));
			sl.add(new Statement(6000,2, "if (rows == undefined || rows == null || rows.length == 0 ){"));
			if (this.domain.getLanguage().equalsIgnoreCase("english")) {
				sl.add(new Statement(7000,3, "$.messager.alert(\"Alert\",\"Please choose one record!\",\"warning\");"));
			}else {
				sl.add(new Statement(7000,3,"$.messager.alert(\"警告\",\"请选定一条记录！\",\"warning\");"));
			}
			sl.add(new Statement(8000,3, "return;"));
			sl.add(new Statement(9000,2, "}"));
			sl.add(new Statement(10000,2, "if (rows.length > 1) {"));
			if (this.domain.getLanguage().equalsIgnoreCase("english")) {
				sl.add(new Statement(11000,3, "$.messager.alert(\"Alert\",\"Please choose one record!\",\"warning\");"));
			}else {
				sl.add(new Statement(11000,3, "$.messager.alert(\"警告\",\"请选定一条记录！\",\"warning\");"));
			}
			sl.add(new Statement(12000,3, "return;"));
			sl.add(new Statement(13000,2, "}"));
			sl.add(new Statement(14000,2, "var "+domain.getDomainId().getLowerFirstFieldName()+" = rows[0][\""+domain.getDomainId().getLowerFirstFieldName()+"\"];"));
			sl.add(new Statement(15000,2, "clone"+this.domain.getCapFirstDomainName()+"("+domain.getDomainId().getLowerFirstFieldName()+");"));
			sl.add(new Statement(16000,1, "}"));
			sl.add(new Statement(17000,0, "}"));
			block.setMethodStatementList(sl);
			return block;		
		}
	}
	@Override
	public JavascriptMethod generateEasyUIJSActionMethod() throws Exception {
		if (this.denied) return null;
		else {
			Domain domain = this.domain;
			Var id = new Var(domain.getDomainId().getLowerFirstFieldName(),new Type("var"));
			JavascriptMethod method = new JavascriptMethod();
			method.setSerial(200);
			method.setStandardName("clone"+domain.getCapFirstDomainName());
			Signature s1 = new Signature();
			s1.setName(id.getVarName());
			s1.setPosition(1);
			s1.setType(new Type("var"));	
			method.addSignature(s1);
			
			StatementList sl = new StatementList();
			sl.add(new Statement(1000,1, "$.ajax({"));
			sl.add(new Statement(2000,2, "type: \"post\","));
			sl.add(new Statement(3000,2, "url: \"../"+this.domain.getControllerPackagePrefix()+domain.getLowerFirstDomainName()+domain.getControllerNamingSuffix()+"/clone"+domain.getCapFirstDomainName()+"\","));
			sl.add(new Statement(4000,2, "data: {"));
			sl.add(new Statement(5000,3, "\""+domain.getDomainId().getLowerFirstFieldName()+"\":"+domain.getDomainId().getLowerFirstFieldName()+"	"));	
			sl.add(new Statement(6000,2, "},"));
			sl.add(new Statement(7000,2, "dataType: 'json',"));
			sl.add(new Statement(8000,2, "success: function(data, textStatus) {"));
			sl.add(new Statement(9000,3, "$(\"#"+this.detailPrefix+"dg\").datagrid(\"load\");"));
			sl.add(new Statement(10000,2, "},"));
			sl.add(new Statement(11000,2, "complete : function(XMLHttpRequest, textStatus) {"));
			sl.add(new Statement(12000,2, "},"));
			sl.add(new Statement(13000,2, "error : function(XMLHttpRequest,textStatus,errorThrown) {"));
			sl.add(new Statement(14000,3, "alert(\"Error:\"+textStatus);"));
			sl.add(new Statement(15000,3, "alert(errorThrown.toString());"));
			sl.add(new Statement(16000,2, "}"));
			sl.add(new Statement(17000,1, "});"));
			
			method.setMethodStatementList(sl);
			return method;	
		}
	}
}
